package signalprocessing;


import java.awt.Cursor;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Set;

import ikelib.ChannelData;
import ikelib.PlotColor;
import ikelib.wintime;

import javax.swing.JPanel;

import wcg.ChannelConfig;
import wcg.ChannelDataCollection;
import wcg.ChannelDataDisplayProperty;
import wcg.winDataBase;
import wcg.winDataBaseChange;
import wcg.winchkgProperty;

/**
 * 
 */

/**
 * winchkgのパネルのベースクラス　
 * @author Toshiharu Ikeda <ikeda.104@gmail.com>
 *
 */
abstract public class SignalProcessingPanelBasic extends JPanel {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	public SignalProcessingPanelBasic(){
		//super();
	}
	protected winDataBase	Data = null;  //@
	private ChannelConfig ChConfig = null;
	private static final String INIT_FILE = "Channel.ini";
	protected PlotColor Col = new PlotColor();

	protected HashMap<Integer,PlotTable> Plot = new HashMap<Integer,PlotTable>();
	/**
	 * 
	 * LinkedList<Integer> <ch> 保持しているｃｈのリスト;
	 */
	protected LinkedList<Integer> AccViewCh = new LinkedList<Integer>();

	
	
	/**
	 * 
	 */
	protected String ExportImageDir=null;
	/**
	 * プロパティのロードとセーブ
	 * @param save
	 */
	public void LoadSaveProperty(boolean save){
		if(save){
			if(ExportImageDir!=null){
				winchkgProperty.TimeSeriesExportImageDir =  ExportImageDir;
			}
		}
		else{
			ExportImageDir = winchkgProperty.TimeSeriesExportImageDir;
		}

	}

	abstract  void doGetChannel();
	/**
	 * win databaseが変化したときに呼び出される。
	 * @param hint
	 * @param ch
	 * @param dcol
	 */
	public void OnChangeDataBase(int hint, int ch, ChannelDataCollection dcol) {
		switch(hint){
		case winDataBaseChange.EVENT_CHANNEL_CLEAR:
		case winDataBaseChange.EVENT_CHANNEL_ADD:
		case winDataBaseChange.EVENT_CHANNEL_REMOVE:
			doGetChannel();
			break;
		case winDataBaseChange.EVENT_DATA_CLEAR:
			break;
		case winDataBaseChange.EVENT_DATA_REMOVE:
			break;
		case winDataBaseChange.EVENT_DATA_PUT:
			//OnChangeData();
			break;
		}
	}
	/**
	 * 
	 * @param ch
	 * @return
	 */
	public boolean isChannelExist(int ch){
		PlotTable tbl = Plot.get(ch);
		if(tbl == null) return false;
		//PlotTemperature v = tbl.AcsView;
		PlotPane v = tbl.AcsView;
		if(v==null){
			return false;
		}
		return true;
	}

	/**
	 * winデータベースをセットする
	 * @param d
	 */
	public void setwinDataBase(winDataBase d){
		Data=d;
	}


	
	/**
	 * ＣＨ生データ 物理データ　を得る
	 * @param id
	 * @return
	 */
	protected double[] getChannelRawData(int id){
		ChannelDataDisplayProperty pro = ChConfig.getData(id);
		double factor=1.0;
		if(pro!=null){
			factor = pro.unitFactor;
		}
		return getChannelRawData(id,factor);
	}
	/**
	 * ＣＨデータを得る
	 * @param id
	 * @return
	 */
	protected double[] getChannelRawData(int id,double factor){
		wintime tm = new wintime(Data.getDispStartTime());
		int span = (int)Data.DispSpanSec;
		ChannelDataCollection dcol = Data.getChannelDataCollection(id);
		if(dcol!=null){
			// すべてのデータを得る。
			
			LinkedList<int[]> d = dcol.getChannelData(tm,span);
			if(d==null){
				tm.inc_sec();
				d = dcol.getChannelData(tm,span);
			}
			if(d!=null){
				//ChannelData cd = dcol.getChannelData(tm);
				//int smp = cd.getSamplerate();
				int len = 0;
				for(int i=0;i<d.size();i++){
					len += d.get(i).length;
				}
				double[] dd = new double[len];
				int index=0;
				for(int i=0;i<d.size();i++){
					int[] idat = d.get(i);
					for(int j=0;j<idat.length;j++){
						dd[index++] = idat[j] * factor;
					}
				}
				return dd;
			}
		}
		return null;
	}

	
	/**
	 * 
	 */
	public abstract void updateChannel();
	/**
	 * 設定が変更されたとき
	 */
	protected void onConfChange() {
		setCursor((Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR )));
		if(ChConfig==null) {
			ChConfig = new ChannelConfig(INIT_FILE);
		}
		ChConfig.load(INIT_FILE);
		updateChannel();
		setCursor((Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR )));
	}
	/**
	 * Yスケールを自動的に合わせる
	 * @param mode
	 */
	protected void doYSpanAuto(int mode) {
		Iterator<Integer> ite = AccViewCh.iterator();
		while(ite.hasNext()){
			int ch = ite.next();
			//	PlotTemperature ac=Plot.get(ch).AcsView;
			PlotPane ac=Plot.get(ch).AcsView;
			ac.setYScaleAuto(mode);
		}
	}
	/**
	 * Xスケールを自動的に合わせる
	 * @param mode
	 */
	protected void doXSpanAuto(int mode) {
		Iterator<Integer> ite = AccViewCh.iterator();
		while(ite.hasNext()){
			int ch = ite.next();
			//PlotTemperature ac=Plot.get(ch).AcsView;
			PlotPane ac=Plot.get(ch).AcsView;
			ac.setXScaleAuto(mode);
		}
	}
	/**
	 * 目盛を丸める
	 */
	protected void doYSpanAutoRoundScale(int r) {
		Iterator<Integer> ite = AccViewCh.iterator();
		while(ite.hasNext()){
			int ch = ite.next();
			//PlotTemperature ac=Plot.get(ch).AcsView;
			PlotPane ac=Plot.get(ch).AcsView;
			ac.setYScaleSpanRound(r);
		}
	}
	/**
	 * シングルスケールを実行する(グループ毎）
	 * @param mode 0: 普通、1: 丸め（1ケタ）,1: 丸め（2ケタ）...
	 */
	protected void doYSpanSingleGroup(int mode) {
		//      CH SUB ID , Listof ID   
		HashMap<Integer,LinkedList<Integer>> sub = new HashMap<Integer,LinkedList<Integer>>();
		//      CH ID , CH SUB ID
		//	HashMap<Integer,Double>  id = new HashMap<Integer,Double>();

		Iterator<Integer> ite = AccViewCh.iterator();
		double span = 0.0;
		// sub ＩＤ毎のグループを作る
		while(ite.hasNext()){
			int ch = ite.next();
			//PlotTemperature ac=Plot.get(ch).AcsView;
			PlotPane ac=Plot.get(ch).AcsView;
			Integer subid = ac.getIdSub(ch&0xffff);
			if(sub.containsKey(subid)){
				sub.get(subid).add(ch);
			}
			else{
				LinkedList<Integer> n = new LinkedList<Integer>();
				n.add(ch);
				sub.put(subid,n);
			}
		}

		Set<Integer> ks = sub.keySet();

		Iterator<Integer> ite2 = ks.iterator();
		while(ite2.hasNext()){
			int subch = ite2.next();
			LinkedList<Integer> lst = sub.get(subch);
			Iterator<Integer> ite3 = lst.iterator();
			double max = 0.0;
			while(ite3.hasNext()){
				int ch = ite3.next();
				//PlotTemperature ac=Plot.get(ch).AcsView;
				PlotPane ac=Plot.get(ch).AcsView;
				double y = ac.getYScaleSpan();
				if(y>max) max=y;
			}

			Iterator<Integer> ite4 = lst.iterator();
			while(ite4.hasNext()){
				int ch = ite4.next();
				//PlotTemperature ac=Plot.get(ch).AcsView;
				PlotPane ac=Plot.get(ch).AcsView;
				ac.setYScaleSpan(max);
				if(mode == 1){
					ac.setYScaleSpanRound(2);
				}

			}
		}
	}
	/**
	 * シングルスケールを実行する
	 * @param mode 0: 普通、1: 丸め（1ケタ）,1: 丸め（2ケタ）...
	 */
	protected void doYSpanSingle(int mode) {
		Iterator<Integer> ite = AccViewCh.iterator();
		double span = 0.0;
		while(ite.hasNext()){
			int ch = ite.next();
			//PlotAccelaration ac=Plot.get(ch).AcsView;
			PlotPane ac=Plot.get(ch).AcsView;
			double s = ac.getYScaleSpan();
			if(s>span) span=s;
		}
		ite = AccViewCh.iterator();
		while(ite.hasNext()){
			int ch = ite.next();
			//PlotAccelaration ac=Plot.get(ch).AcsView;
			PlotPane ac=Plot.get(ch).AcsView;
			ac.setYScaleSpan(span);
			if(mode == 1){
				ac.setYScaleSpanRound(mode-1);
			}
		}
	}

	/**
	 * truncate を実行する
	 * @param mode 0: 普通、1: 丸め（1ケタ）,1: 丸め（2ケタ）...
	 */
	protected void doYSpanTruncate(int mode) {
		Iterator<Integer> ite = AccViewCh.iterator();
		while(ite.hasNext()){
			int ch = ite.next();
			//PlotTemperature ac=Plot.get(ch).AcsView;
			PlotPane ac=Plot.get(ch).AcsView;
			ac.setYScaleSpanRound(mode);
		}
	}
	/**
	 * truncate を実行する
	 * @param mode 0: 普通、1: 丸め（1ケタ）,1: 丸め（2ケタ）...
	 */
	protected void doXSpanTruncate(int mode) {
		Iterator<Integer> ite = AccViewCh.iterator();
		while(ite.hasNext()){
			int ch = ite.next();
			//PlotTemperature ac=Plot.get(ch).AcsView;
			PlotPane ac=Plot.get(ch).AcsView;
			ac.setXScaleSpanRound(mode);
		}
	}
	/**
	 * Y軸をシフトする
	 * @param sft ％で指定、＋でセンターが＋（波形は下）
	 */
	protected void doYShift(int sft) {
		Iterator<Integer> ite = AccViewCh.iterator();
		while(ite.hasNext()){
			int ch = ite.next();
			//PlotTemperature ac=Plot.get(ch).AcsView;
			PlotPane ac=Plot.get(ch).AcsView;
			ac.setYScaleShift(sft);
		}
	}
	/**
	 * X軸を進め、遅らす （＋進める、－遅らす）
	 * @param forward　%で指定する
	 */
	protected void doXShift(int forward) {
		Iterator<Integer> ite = AccViewCh.iterator();
		while(ite.hasNext()){
			int ch = ite.next();
			//PlotTemperature ac=Plot.get(ch).AcsView;
			PlotPane ac=Plot.get(ch).AcsView;
			ac.setXScaleShift(forward);
		}
	}
	/**
	 * Y拡大縮小する
	 * @param radio
	 */
	protected void doYSpan(int radio) {
		Iterator<Integer> ite = AccViewCh.iterator();
		while(ite.hasNext()){
			int ch = ite.next();
			//PlotTemperature ac=Plot.get(ch).AcsView;
			PlotPane ac=Plot.get(ch).AcsView;
			ac.setYScaleUpDown(radio);
		}
	}
	/**
	 * Yを指定値にセットする。 （最大値＜最小値なら自動的に入れ替える）
	 * @param max 最大値　
	 * @param min 最小値
	 */
	protected void doYSpan(double max,double min) {
		Iterator<Integer> ite = AccViewCh.iterator();
		while(ite.hasNext()){
			int ch = ite.next();
			PlotPane ac=Plot.get(ch).AcsView;
			ac.setYScaleMaxMin(max,min);
		}
	}
	/**
	 * X拡大縮小する
	 * @param radio
	 */
	protected void doXSpan(int radio) {
		Iterator<Integer> ite = AccViewCh.iterator();
		while(ite.hasNext()){
			int ch = ite.next();
			//PlotTemperature ac=Plot.get(ch).AcsView;
			PlotPane ac=Plot.get(ch).AcsView;
			ac.setXScaleUpDown(radio);
		}
	}
	/**
	 * 振幅をシフトする
	 * @param sft ％で指定、＋でセンターが＋（波形は下）
	 */
	protected void doYSpanShift(int sft) {
		Iterator<Integer> ite = AccViewCh.iterator();
		while(ite.hasNext()){
			int ch = ite.next();
			//PlotAccelaration ac=Plot.get(ch).AcsView;
			PlotPane ac=Plot.get(ch).AcsView;
			ac.setYScaleShift(sft);
		}
	}
	/**
	 * 時間軸をズームする。
	 * @param r　%で指定する　-ズームイン +ズームアウト
	 */
	protected void doTSpanZoom(int r) {
		Iterator<Integer> ite = AccViewCh.iterator();
		while(ite.hasNext()){
			int ch = ite.next();
			//PlotAccelaration ac=Plot.get(ch).AcsView;
			PlotPane ac=Plot.get(ch).AcsView;
			ac.incViewTimeSpan(r);
		}
	}
	protected void doTSpanAuto() {
		Iterator<Integer> ite = AccViewCh.iterator();
		while(ite.hasNext()){
			int ch = ite.next();
			//PlotAccelaration ac = Plot.get(ch).AcsView;
			PlotPane ac = Plot.get(ch).AcsView;
			ac.setTimeSpanAuto(true);
		}
	}


	/**
	 * 時間軸を進め、遅らす （＋進める、－遅らす）
	 * @param forward　%で指定する
	 */
	protected void doTShift(int forward) {
		Iterator<Integer> ite = AccViewCh.iterator();
		while(ite.hasNext()){
			int ch = ite.next();
			//PlotAccelaration ac=Plot.get(ch).AcsView;
			PlotPane ac=Plot.get(ch).AcsView;
			ac.incViewTimeStart(forward);
		}
	}

	
	/**
	 * 生データのサンプルレートを得る
	 * @param id
	 * @return
	 */
	protected int getRawSampleRate(int id){
		// TODO １秒から始まるデータで、普通にgetDispStartTimeしても、正分の時刻しか返さない。とりあえず、サーチしてデータのある時刻から計算をする。
		//wintime tm = new wintime(Data.getDispStartTime());
		wintime tmp = Data.getDispStartTime(id);
		if(tmp == null) return -1;
		wintime tm = new wintime(tmp);
		ChannelDataCollection dcol = Data.getChannelDataCollection(id);
		if(dcol!=null){
			ChannelData cd = dcol.getChannelData(tm);
			if(cd != null)	return cd.getSamplerate();
		}
		return -1;
	}


	
	
}
